From bd35714f3e5098b6f100e0f145d96acea0b78256 Mon Sep 17 00:00:00 2001 From: "arun.sharma@intel.com[kaf24]" Date: Wed, 20 Apr 2005 10:25:15 +0000 Subject: [PATCH] bitkeeper revision 1.1336 (42662e0bB62AMXvz0XCbYomA5_OHAw) [PATCH] x86-64-enable-vmx.patch Enable CONFIG_VMX for x86_64. - Provides vmexit/entry handling code based on the x86_32 code - Fix find_highest_vector for 64 bit (Benjamin Liu) Signed-off-by: Arun Sharma --- xen/arch/x86/Makefile | 4 -- xen/arch/x86/vmx.c | 5 ++ xen/arch/x86/vmx_intercept.c | 2 +- xen/arch/x86/vmx_io.c | 65 ++++++++++++++--- xen/arch/x86/vmx_vmcs.c | 13 ++++ xen/arch/x86/x86_64/entry.S | 133 +++++++++++++++++++++++++++++++++++ xen/include/asm-x86/config.h | 2 - 7 files changed, 206 insertions(+), 18 deletions(-) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 0281991c0d..42d828f7f5 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -7,10 +7,6 @@ OBJS += $(patsubst %.c,%.o,$(wildcard mtrr/*.c)) OBJS := $(subst $(TARGET_SUBARCH)/asm-offsets.o,,$(OBJS)) -ifneq ($(TARGET_SUBARCH),x86_32) -OBJS := $(patsubst vmx%.o,,$(OBJS)) -endif - ifneq ($(crash_debug),y) OBJS := $(patsubst cdb%.o,,$(OBJS)) endif diff --git a/xen/arch/x86/vmx.c b/xen/arch/x86/vmx.c index 8093bd0c3f..cc560b4462 100644 --- a/xen/arch/x86/vmx.c +++ b/xen/arch/x86/vmx.c @@ -959,7 +959,12 @@ asmlinkage void load_cr2(void) struct exec_domain *d = current; local_irq_disable(); +#ifdef __i386__ asm volatile("movl %0,%%cr2": :"r" (d->arch.arch_vmx.cpu_cr2)); +#else + asm volatile("movq %0,%%cr2": :"r" (d->arch.arch_vmx.cpu_cr2)); +#endif + } #endif /* CONFIG_VMX */ diff --git a/xen/arch/x86/vmx_intercept.c b/xen/arch/x86/vmx_intercept.c index 11ee2bb2fb..81b3f789fd 100644 --- a/xen/arch/x86/vmx_intercept.c +++ b/xen/arch/x86/vmx_intercept.c @@ -37,7 +37,7 @@ int vmx_io_intercept(ioreq_t *p) struct exec_domain *d = current; struct vmx_handler_t *handler = &(d->arch.arch_vmx.vmx_platform.vmx_handler); int i; - unsigned addr, offset; + unsigned long addr, offset; for (i = 0; i < handler->num_slot; i++) { addr = handler->hdl_list[i].addr; offset = handler->hdl_list[i].offset; diff --git a/xen/arch/x86/vmx_io.c b/xen/arch/x86/vmx_io.c index c8ba11c494..70b62dceb1 100644 --- a/xen/arch/x86/vmx_io.c +++ b/xen/arch/x86/vmx_io.c @@ -169,6 +169,17 @@ static void set_reg_value (int size, int index, int seg, struct xen_regs *regs, break; } } +#else +static void load_xen_regs(struct xen_regs *regs) +{ + /* XXX: TBD */ + return; +} +static void set_reg_value (int size, int index, int seg, struct xen_regs *regs, long value) +{ + /* XXX: TBD */ + return; +} #endif void vmx_io_assist(struct exec_domain *ed) @@ -271,7 +282,8 @@ void vmx_io_assist(struct exec_domain *ed) } } -static inline int __fls(unsigned long word) +#ifdef __i386__ +static inline int __fls(u32 word) { int bit; @@ -280,26 +292,57 @@ static inline int __fls(unsigned long word) :"rm" (word)); return word ? bit : -1; } +#else +#define __fls(x) generic_fls(x) +static __inline__ int generic_fls(u32 x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} +#endif /* Simple minded Local APIC priority implementation. Fix later */ -static __inline__ int find_highest_irq(unsigned long *pintr) +static __inline__ int find_highest_irq(u32 *pintr) { if (pintr[7]) - return __fls(pintr[7]) + (256-32*1); + return __fls(pintr[7]) + (255-32*1); if (pintr[6]) - return __fls(pintr[6]) + (256-32*2); + return __fls(pintr[6]) + (255-32*2); if (pintr[5]) - return __fls(pintr[5]) + (256-32*3); + return __fls(pintr[5]) + (255-32*3); if (pintr[4]) - return __fls(pintr[4]) + (256-32*4); + return __fls(pintr[4]) + (255-32*4); if (pintr[3]) - return __fls(pintr[3]) + (256-32*5); + return __fls(pintr[3]) + (255-32*5); if (pintr[2]) - return __fls(pintr[2]) + (256-32*6); + return __fls(pintr[2]) + (255-32*6); if (pintr[1]) - return __fls(pintr[1]) + (256-32*7); - return __fls(pintr[0]); + return __fls(pintr[1]) + (255-32*7); + return (__fls(pintr[0])-1); } /* @@ -317,7 +360,7 @@ static inline int find_highest_pending_irq(struct exec_domain *d) domain_crash_synchronous(); } - return find_highest_irq(&vio->vp_intr[0]); + return find_highest_irq((unsigned int *)&vio->vp_intr[0]); } static inline void clear_highest_bit(struct exec_domain *d, int vector) diff --git a/xen/arch/x86/vmx_vmcs.c b/xen/arch/x86/vmx_vmcs.c index 0d2e79743d..512846c4b7 100644 --- a/xen/arch/x86/vmx_vmcs.c +++ b/xen/arch/x86/vmx_vmcs.c @@ -327,7 +327,11 @@ construct_init_vmcs_guest(execution_context_t *context, error |= __vmwrite(GUEST_EFLAGS, eflags); error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); +#ifdef __i386__ __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7)); +#else + __asm__ __volatile__ ("movq %%dr7, %0\n" : "=r" (dr7)); +#endif error |= __vmwrite(GUEST_DR7, dr7); error |= __vmwrite(GUEST_VMCS0, 0xffffffff); error |= __vmwrite(GUEST_VMCS1, 0xffffffff); @@ -363,12 +367,21 @@ static inline int construct_vmcs_host(struct host_execution_env *host_env) host_env->idtr_base = desc.address; error |= __vmwrite(HOST_IDTR_BASE, host_env->idtr_base); +#ifdef __i386__ __asm__ __volatile__ ("movl %%cr0,%0" : "=r" (crn) : ); +#else + __asm__ __volatile__ ("movq %%cr0,%0" : "=r" (crn) : ); +#endif + host_env->cr0 = crn; error |= __vmwrite(HOST_CR0, crn); /* same CR0 */ /* CR3 is set in vmx_final_setup_hostos */ +#ifdef __i386__ __asm__ __volatile__ ("movl %%cr4,%0" : "=r" (crn) : ); +#else + __asm__ __volatile__ ("movq %%cr4,%0" : "=r" (crn) : ); +#endif host_env->cr4 = crn; error |= __vmwrite(HOST_CR4, crn); error |= __vmwrite(HOST_EIP, (unsigned long) vmx_asm_vmexit_handler); diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 5cee142c18..9254cf76e4 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -151,6 +151,139 @@ test_all_events: movb $1,VCPUINFO_upcall_mask(%rax) # Upcalls masked during delivery jmp test_all_events +#ifdef CONFIG_VMX +/* + * At VMExit time the processor saves the guest selectors, rsp, rip, + * and rflags. Therefore we don't save them, but simply decrement + * the kernel stack pointer to make it consistent with the stack frame + * at usual interruption time. The rflags of the host is not saved by VMX, + * and we set it to the fixed value. + * + * We also need the room, especially because orig_eax field is used + * by do_IRQ(). Compared the xen_regs, we skip pushing for the following: + * (13) u64 gs_base_user; + * (12) u64 gs_base_kernel; + * (11) u64 fs_base; + * (10) u64 gs; + * (9) u64 fs; + * (8) u64 ds; + * (7) u64 es; + * <- get_stack_bottom() (= HOST_ESP) + * (6) u64 ss; + * (5) u64 rsp; + * (4) u64 rflags; + * (3) u64 cs; + * (2) u64 rip; + * (2/1) u32 entry_vector; + * (1/1) u32 error_code; + * However, get_stack_bottom() actually returns 64 bytes before the real + * bottom of the stack to allow space for: + * domain pointer, DS, ES, FS, GS. Therefore, we effectively skip 6 registers. + */ +#define VMX_MONITOR_RFLAGS 0x202 /* IF on */ +#define NR_SKIPPED_REGS 6 /* See the above explanation */ +#define VMX_SAVE_ALL_NOSEGREGS \ + pushq $VMX_MONITOR_RFLAGS; \ + popfq; \ + subq $(NR_SKIPPED_REGS*8), %rsp; \ + pushq %rdi; \ + pushq %rsi; \ + pushq %rdx; \ + pushq %rcx; \ + pushq %rax; \ + pushq %r8; \ + pushq %r9; \ + pushq %r10; \ + pushq %r11; \ + pushq %rbx; \ + pushq %rbp; \ + pushq %r12; \ + pushq %r13; \ + pushq %r14; \ + pushq %r15; \ + +ENTRY(vmx_asm_vmexit_handler) + /* selectors are restored/saved by VMX */ + VMX_SAVE_ALL_NOSEGREGS + call SYMBOL_NAME(vmx_vmexit_handler) + jmp vmx_asm_do_resume + +ENTRY(vmx_asm_do_launch) + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rax + popq %rcx + popq %rdx + popq %rsi + popq %rdi + addq $(NR_SKIPPED_REGS*8), %rsp + /* VMLUANCH */ + .byte 0x0f,0x01,0xc2 + pushfq + call SYMBOL_NAME(vm_launch_fail) + hlt + + ALIGN + +ENTRY(vmx_asm_do_resume) +vmx_test_all_events: + GET_CURRENT(%rbx) +/* test_all_events: */ + xorq %rcx,%rcx + notq %rcx + cli # tests must not race interrupts +/*test_softirqs:*/ + movq EDOMAIN_processor(%rbx),%rax +#if 0 + shl $6,%rax # sizeof(irq_cpustat) == 64 + test %rcx,SYMBOL_NAME(irq_stat)(%rax,1) +#endif + jnz vmx_process_softirqs + +vmx_restore_all_guest: + call SYMBOL_NAME(load_cr2) + /* + * Check if we are going back to VMX-based VM + * By this time, all the setups in the VMCS must be complete. + */ + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rax + popq %rcx + popq %rdx + popq %rsi + popq %rdi + addq $(NR_SKIPPED_REGS*8), %rsp + /* VMRESUME */ + .byte 0x0f,0x01,0xc3 + pushfq + call SYMBOL_NAME(vm_resume_fail) + /* Should never reach here */ + hlt + + ALIGN +vmx_process_softirqs: + sti + call SYMBOL_NAME(do_softirq) + jmp vmx_test_all_events +#endif + ALIGN /* %rbx: struct exec_domain */ process_softirqs: diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index 4a85112244..2b20297a6e 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -7,9 +7,7 @@ #ifndef __X86_CONFIG_H__ #define __X86_CONFIG_H__ -#ifdef __i386__ #define CONFIG_VMX 1 -#endif #define CONFIG_X86 1 #define CONFIG_SHADOW 1 -- 2.30.2